        .PAGE
        .IF     EXTERNAL = 1
        .LIST
        .ENDC
        .IF  USERINT = 1
;**********************************
;  Mini-Graphics Package	  *
;  Contributed by Mike Urquhart	  *
;  Copyright 1983, 1984 Apple	  *
;**********************************

;________________________________________________________________________________
;
;       DRAWDESK:
;
;	        this routine performs the following sequences:
;
;	        1.      clears the screen to a white background.
;	        2.      makes a menu bar by drawing a single pixel horizontal
;		        line across the screen.
;	        3.      fills the screen area below the menu bar with the stantard
;		        gray shade.
;
;	        Also has an entry point called CLRDESK that only does item (3).
;
;   Destroys regs D0-D2,A1,A5-A6
;________________________________________________________________________________


;
;       1.      clear screen to white background

DRAWDESK
        clr.l   d2
        bsr.s   whiten

;
;       2.      make menu bar border

CLRDESK moveq   #ROWBYTES,d0    ;set length of line = 90 bytes
        moveq   #-1,d2	        ;draw a black pattern
        move.w  #MENULINE,A1    ;start at offset 1440 address
        moveq   #1,d1	        ;draw only 1 pixel line
        bsr.s   paint_box

;
;       set a6 to starting pixel address for grey routine below
;       set a5 to limit
;
        move    #DESKLINE,a6
        move    #DESKLMT,a5     ;set limit

;
;       3.      make the grey background: to make the gray background, alternating
;	        rows of $5555 and $AAAA starting with $AAAA are written to the
;	        screen area.
;

gray    MOVE.L  #DESKPATRN,D2   ;set up grey pattern

gray1   swap    d2	        ;start with the $AAAA pattern
        moveq   #1,d1	        ;draw a one pixel high line
        move.l  a6,a1	        ;starting pixel address must be in a1 for call
        bsr     paint_box

@1      add     d0,a6	        ;bump to next pixel line
        cmp.w   a5,a6	        ;is a6 less then max?
        blt.s   gray1		      ;loop if yes
        rts			      ;else done

;_________________________________________________________________________
;
;       subroutine blacken and whiten: clears full screen to black or white
;
;       Calls:  bsr     blacken	        (no parameters)
;
;	        clr.l   d2
;	        bsr     whiten
;
;       registers used:	  d2.l - contains either FFFFFFFF or 0 on return
;			  d0.b - destroyed but contains $5A (90) on return
;			  d1.w - destroyed-->should contain 0 on return
;			  a1.l - destroyed
;
;
;       This routine calls paint_box, so other registers may be destroyed.
;
;
;_________________________________________________________________________


BLACKEN
        moveq   #-1,d2		        ;black fill pattern

whiten
        move.w  #MaxY-1,d1	        ;number of pixels in screen box heigth
        moveq   #ROWBYTES,d0	        ;length of screen box is 90 bytes
        suba.l  A1,A1		        ;clear A1
        bsr.s   paint_box
        rts

;------------------------------------------------------------------------
;  Subroutine to clear only menu bar on desktop
;  Inputs:
;       None
;  Outputs:
;       None
;  Side Effects:
;       None
;------------------------------------------------------------------------

CLRMENU MOVEM.L D0-D2/A1,-(SP)  ;save regs
        MOVEQ   #ROWBYTES,D0    ;width of menu bar is 90 bytes
        MOVEQ   #MBARLEN,D1     ;heigth is 15 pixels
        MOVEQ   #0,D2	        ;set fill pattern
        SUBA.L  A1,A1	        ;upper left corner is at offset 0
        BSR.S   PAINT_BOX       ;go do it
        MOVEM.L (SP)+,D0-D2/A1  ;restore and
        RTS		        ; exit

;________________________________________________________________________________
;
;       Routine paint_box
;
;       Call:	     BSR   paint_box
;		  or
;		     BSR   paintb2
;
;       register setup:
;
;       D2 must contain a one word fill pattern.
;       D0 must contain the width of the box(horizontally) or the length of
;		        the line.
;       D1 must contain the heigth(vertically of the box) in horizontal pixel
;		        rows:
;       A1 must contains the screen displacement in the range 0..32670
;
;       __________________________________
;       .				 .
;       .	    fill pattern	 . <-------heigth in pixels
;       __________________________________
;		        ^
;		        ........... length horizontally
;
;       Assumptions:  location SCRNBASE contains the video address
;
;       registers used-->D0-D3,A0-A2
;________________________________________________________________________________


PAINT_BOX

paintb1 lea     movinst,A4
        bra.s   cont

inverse lea     exclusive,A4
cont    ADD.L   SCRNBASE,A1     ;add video address to starting pixel address offset.

paintb2
        MOVE.L  A2,-(SP)        ;save reg
;       do some setup steps
;
        CLR.L   D3	        ;clear for use
        MOVE.W  D0,D3	        ;modify width/length
        NEG.l   D3	        ;negate the width/length (D3 = -width/length)
;
;       add the length of one horizontal pixel row-2 to the -width/length
;       to derive an offset which can be added to the updated address pointer
;       (when it reflects the right corner or end point of the box/line)
;       in order to arrive at the next row starting address.
;
        ADDI.l	 #ROWBYTES,D3   ;create displacement for following sequence
;
;
;
        MOVE.L  A1,A2	        ;create ending column check address
        ADD.L   D0,A2	        ;add length of line to obtain ending column address
;
;       A1 now points to the left top coordinate of the box or line.
;       A2 now points to the right top coordinate of the box or line.
;

startop
        jmp     (A4)	        ;execute the correct operation (EOR or MOVE)

movinst
        MOVE.w  D2,(A1)+        ;start the sequence
        bra.s   compare

exclusive
        eor.w   D2,(A1)+

compare CMP.L   A1,A2	        ;reached the right most point?
        BEQ.S   nextline        ;yes
        BRA.S   startop
;
;       YES
;
nextline
        ADD.L   D3,A1	        ;add 1 horizontal line length (5A) minus line length
        ADDA    #ROWBYTES,A2    ;to reach the left most point of the box on the	        RM000
        SUBQ.W  #1,D1	        ;next horizontal scan line.
        BNE.S   startop	        ;loop until done.
;
        MOVE.L (SP)+,A2	        ;restore and
        RTS		        ;return

;------------------------------------------------------------------------
;  Entry point to set cursor ptrs and make alert box for power cycling
;------------------------------------------------------------------------

MAKEPCALRT
        MOVEQ   #PCROW,D5       ;set row ptr
        MOVEQ   #PCCOL,D6       ;and col ptr
                                ;then drop into alert box routine
;________________________________________________________________________
;
;       MAKEALERT
;
;	        This routine creates an alert box with no title.
;________________________________________________________________________

MAKEALERT
        movem.l d0-d1/a1,-(sp)

        MOVEQ   #ALRTWIDTH,D0	        ;set parameters for box
        MOVE.L  #ALRTHIGH,D1
        MOVEA   #ALRTSTRT,A1
        bsr.s   makebox

        movem.l (sp)+,d0-d1/a1
        rts

;________________________________________________________________________
;
;       MAKETEST
;
;	        This routine creates an alert box for test icon display.
;________________________________________________________________________

MAKETEST
        movem.l d0-d1/a1,-(sp)

        MOVEQ   #TSTWWIDTH,D0	        ;set parameters for alert box
        MOVEQ   #TSTWHIGH,D1
        MOVEA   #TSTWSTRT,A1
        BSR.S   MAKEBOX		        ;go draw box

        MOVEQ   #TSTMROW,D5	        ;set cursor ptrs
        MOVEQ   #TSTMCOL,D6
        LEA     CHKMSG,A3	        ;set message ptr
        MOVEQ   #-1,D1		        ;append '...' string
        BSR     DSPSTRING	        ;and go display it

        BSR     DSPCPU		        ;display test icons
        BSR     DSPIOB
        BSR     DSPMBRD
        BSR     DSPXCRD

        movem.l (sp)+,d0-d1/a1
        rts

;________________________________________________________________________
;
;       MAKEDBOX
;
;	        This routine creates a dialog box.
;________________________________________________________________________

MAKEDBOX
        movem.l d0-d1/a1,-(sp)

        MOVEQ   #DBOXWIDTH,D0	        ;set parameters for dialog box
        MOVEQ   #DBOXHIGH,D1
        MOVEA   #DBOXSTRT,A1
        bsr.s   makebox

        movem.l (sp)+,d0-d1/a1
        rts

;________________________________________________________________________
;
;       routine makewindow
;
;	        This routine creates a fixed window of the folder type.
;	        The calling routine must provide the address of the
;	        string which will be used to fill in the title box.
;
;       Call:
;	        move    <window width>,d0
;	        move    <window heigth>,d1
;	        move    <upper left corner address>,a1
;	        lea     <string address>,a3
;	        bsr     makewindow
;
;       This routine calls makebox
;
;________________________________________________________________________

MAKEWINDOW
        movem.l d0-d1/a1,-(sp)

        bsr.s   makebox

;
;       now draw the title box by drawing a single black line across
;       the width of the window about 17 pixels from the top edge
;

        MOVE.L  A1,-(SP)        ;save start point
        add.w   #MENULINE,a1
        moveq   #1,d1	        ;set heigth of one pixel
        moveq   #-1,d2
        bsr.s   paint_box

        MOVE.L  (SP)+,A1        ;restore start point
        bsr     writetitle

        movem.l (sp)+,d0-d1/a1  ;restore and return
        rts

;________________________________________________________________________
;
;       Routine makebox;
;
;	        This routine creates a window of either the folder type
;	        or the dialog box type.	 Is is the responsibility of
;	        the calling process to append the title box and title
;	        to the window if it is the folder type.
;
;       Call:
;	        move.w  <window width>,d0	        (range 0..90) even
;	        move.w  <window heigth>,d1	        (range 0..364)
;	        move.w  <startingpixeladdress>,a1       (range 0..32670)
;	        bsr     makebox
;
;       registers used: d0,d1,d2,d3,d4,a1,a2
;________________________________________________________________________


MAKEBOX
;
;       make the basic window--->no edges  D2 must be set to 0 on call
;					   d0 must be set to the width (90 maximum)
;					   d1 must be set to the heigth (364 maximum)
;					   A1 must be the offset address (0..32670)
;
;
        movem.l d0-d4/a1-a4,-(sp)
        movem.l d0-d1/a1,-(sp)	   ;save the heigth and the starting pixel address

        clr.l   d2		   ;the pattern
        bsr     paint_box
;
;       now draw the individual edges including the shadow edges on the right
;       and bottom of the window
;

;
;       draw bottom horizontal edge
;
        sub.l   d3,a1
        sub.l   d0,a1	        ;a1 is currently equal to the lower right point
                                ; of the box so we can subtract the width to
                                ; calculate the lower left point of the box.

        moveq   #1,d1	        ;set 1 pixel heigth
        moveq   #-1,d2	        ;set the line pattern
        bsr     paintb2	        ;remember a4 is set up to point to the move.w
                                ; instruction
;
;       draw bottom horizontal shadow
;
@1      addq    #2,a1	        ;shadow begin offset by 2
        moveq   #1,d1	        ;draw a one pixel line
        subq    #2,d0
        bsr     paintb2	        ;go
;
;       draw top horizontal edge
;
@2      movem.l	 (sp)+,d0-d1/a1 ;restore original parameters
        movem.l	 d1/a1,-(sp)
        moveq   #1,d1	        ;draw a 1 pixel line
        bsr     paint_box
;
;       now draw the right edge plus the right edge's shadow, use a1
;       with a column parameter of 0
;
        movem.l	 (sp)+,d4/a2
        moveq   #1,d2
        subq    #2,d4
        subq    #2,d0
        add.l   d0,a1

        move.l  d4,d1
        clr.l   d0
        bsr.s   paint_v

        move.w  #182,d0	        ;set one byte offset from right edge
        moveq   #7,d2
        move.l  d4,d1
        bsr.s   paintbit        ;draw first pixel line of the right shadow

        move.w  #272,d0
        moveq   #6,d2
        move.l  d4,d1
        subq    #1,d1	        ;reduce heigth by 1 to compensate for shadow offset
        bsr.s   paintbit

;
;       now draw the left vertical edge of the box
;
        move.l  a2,a1	        ;restore the starting pixel address
        add.l   SCRNBASE,a1     ;add in video address
        moveq   #90,d0
        add.l   d0,a1
        move    #32768,d2       ;set the pattern

        move.l  d4,d1	        ;the heigth minus two
        clr.l   d0	        ;column 0 offset
        bsr.s   paint_v
        movem.l (sp)+,d0-d4/a1-a4

        rts

;_________________________________________________________________________
;
;       Routine paint_v
;
;       This routine "paints" a vertical column one word wide.
;
;       Call:   BSR     paint_v
;
;       register setup:
;
;       A1 must contain the screen base address.
;       D2 must contain a one word pattern.
;       D1 must contain the number of pixels in the vertical length of the line
;	  in the range 1..364
;       D0 must contain the screen word column in the range 0..44
;
;       Assumptions:  location SCRNBASE contains the video address
;
;       registers used: D0-D1
;________________________________________________________________________
;

PAINT_V

paintv1

@1      MOVE.W  D2,0(A1,D0.W)   ;write to screen
        SUBQ.W  #1,D1	        ;decrement count
        BEQ.S   @2	        ;return
        ADDI.W  #ROWBYTES,D0    ;bump to next horizontal line
        BRA.S   @1	        ;loop to continue writing vertical.
;
@2      RTS		        ;return

;_________________________________________________________________________
;
;       Routine paintbit
;
;       This routine "paints" a vertical line one bit wide.
;
;       Call:   BSR     paintbit
;
;       register setup:
;
;       A1 must contain the screen base address.
;       D2 must contain the bit number to set
;       D1 must contain the number of pixels in the vertical length of the line
;	  in the range 1..364
;       D0 must contain the screen word column in the range 0..44
;
;       Assumptions:  location SCRNBASE contains the video address
;
;       registers used: D0-D1
;________________________________________________________________________

PAINTBIT

@1      bset    d2,0(a1,d0.w)
        subq.w  #1,d1	        ;subtract one from heigth
        beq.s   @2	        ;done

        addi.w  #ROWBYTES,d0    ;increment to next pixel row.
        bra.s   @1

@2      RTS		        ;return

;______________________________________________________________________
;
;       Routine makebutton --> creates a black lined box of the size
;			       specified by the parameters with button
;			       "label" and description if specified.
;			       Also makes entries in active rectangle
;			       table for later use with mouse.
;
;			       the left top corner is addressed by a1,
;			       the alternate keycode is contained in d0.
;			       the description is in A3.
;			       description location is in A2.
;			       '...' string appended to message if d1 nonzero
;
;
;       Call:
;
;	        move.w  <left/top corner point>,a1
;	        move.b  <alternate keycode>,d0
;	        lea     <button description>,a3
;	        move.l  <description location>,a2
;	        <set d1 for '...' string>
;	        bsr     makebutn
;
;       Destroys regs D0-D2,D5,D6,A3
;______________________________________________________________________


MAKEBUTN
        MOVEM.L D1/A2,-(SP)     ;save string indicator and location ptr
        LEA     RectTable,A2    ;get ptr to active rect table
        MOVE    (A2),D2	        ;get current count of rect's
        MULU    #5,D2	        ;five entries per rect
        ADD     D2,D2	        ;double for word index
        ADDQ    #1,(A2)+        ;incr for new rect
        MOVE    D0,0(A2,D2.W)   ;save keycode id for new rect
        BSR     KeyToAscii      ;convert keycode to Ascii
        MOVE    D0,D4	        ;save for later display

;  compute X,Y pixel coordinates from starting address

        BSR     GETROWCOL       ;get pixel row, byte col
        MULU    #8,D6	        ;convert to pixel col
        MOVE    D6,2(A2,D2.W)   ;save upper left X
        MOVE    D5,4(A2,D2.W)   ; and Y coordinates

        MOVEQ   #BTNWIDTH,D0    ;set button parameters
        MOVEQ   #BTNHIGH,D1
        BSR.S   DRAWBUTN        ;draw the button

        MOVE.L  A1,-(SP)        ;save original val
        MOVE    LwrRight,a1     ;compute lower right coordinates
        BSR     GETROWCOL       ;get pixel row
        MULU    #8,D6	        ;and pixel col
        MOVE    D6,6(A2,D2.W)   ;save as X and
        MOVE    D5,8(A2,D2.W)   ; Y coordinates
        MOVE.L  (SP)+,A1        ;restore starting value

;       Add the button label and description

        movem.l d0-d4/a1-a3,-(sp)  ;save parameters

        lsr.l   #1,d0	        ;divide window width
        bsr     getrowcol       ;get the row and column coordinate of
                                ;the window corner point
        add.l   d0,d6	        ;adjust column pointer

        lsr.l   #1,d1	        ;divide window heigth
        subq.l  #4,d1	        ;decrement by half font heigth
        add.l   d1,d5	        ;adjust row coordinate

        SUBQ    #1,D6	        ;go back 1 and
        CLR     D0	        ;display apple icon
        BSR     DSPVAL

        MOVE.L  D4,D0	        ;get char to display
        bsr     dspval	        ;and go display alternate keycode

        movem.l (sp)+,d0-d4/a1-a3  ;retrieve parameters
        MOVEM.L (SP)+,D1/A2	   ;retrieve location and string indicator

        MOVE.L  A2,A1	        ;compute output pt for description
        BSR     GETROWCOL
        BSR     DSPSTRING       ;and display it

        RTS

;______________________________________________________________________
;
;       Routine drawbutton --> creates a black lined box of the size
;			       specified by the parameters.
;
;			       the left top corner is addressed by a1,
;			       the width is indicated by d0.
;			       the heigth is indicated by d1.
;
;
;	      this routine calls paint_box, and paintbit.
;
;	        inputs:	        d0=window width in bytes (should be even)
;			        d1=heigth in pixels
;			        a1=window left/top corner point as a
;				   0..32670 screen offset address.
;
;       Call:
;
;	        move.w  <left/top corner point>,a1
;	        move.w  <button width>,d0
;	        move.w  <button height>,d1
;	        bsr     drawbutn
;______________________________________________________________________

DRAWBUTN
        movem.l d0-d4/a1-a3,-(sp)  ;stack the arguments
;
;
;       draw the top edge of the button
;

        moveq   #-1,d2	        ;set the black bit pattern for paint_box
        moveq   #1,d1	        ;set a 1 pixel line
        bsr     paint_box

;
;       draw the right vertical edge of the button
;
        sub.l   d3,a1	        ;on return from paint_box, a1 points to the
                                ;real address of the left point of the next
                                ;horizontal pixel line of the button, so d3,
                                ;which contains the displacement to the prior
                                ;lines right edge is added to the
                                ;left point to obtain the correct
                                ;address for the right edge.
        move.l  4(sp),d1        ;momentarily restore the heigth
        clr.l   d0
        moveq   #7,d2	        ;set the 1 bit mask for paintbit
        bsr.s   paintbit        ;draw the right edge

;
;       now draw the left edge of the button
;
        move.l  20(sp),a1       ;restore the original corner point
        add.l   SCRNBASE,a1     ;add in the screen window address

        move.l  4(sp),d1        ;restore the heigth
        clr.l   d0
        moveq   #7,d2	        ;set the 1 bit mask for the left edge
        bsr.s   paintbit

;
;       now draw the bottom edge of the button
;
        add.l   d0,a1	        ;add the displacement to the corner point to arrive
                                ;at the correct address of the bottom left corner
        move.l  (sp),d0	        ;restore the width
        moveq   #1,d1	        ;set the heigth at 1.
        moveq   #-1,d2	        ;set the line pattern to black
        bsr     paintb2
;
;       done - save lower right coordinate
;
        sub.l   d3,a1	        ;get offset address for lower right corner
        sub.l   SCRNBASE,a1
        move    a1,LwrRight     ;save it
        movem.l (sp)+,d0-d4/a1-a3
        rts

;____________________________________________________________________
;
;       Routine to redraw the sides of a pulldown menu item.
;
;       Call:   move.w  <width of box>,d0
;	        move.w  <heigth of box>,d1
;	        move.l  <pixeladdress>,a1
;	        jsr     inversmenuitem
;
;____________________________________________________________________

DRAWSIDES
        movem.l d0-d1/a1,-(sp)

;       redraw the left vertical edge of the pull down menu

        add.l   SCRNBASE,a1     ;add in the real video window address
        moveq   #7,d2	        ;set the bit for paintbit
        clr.l   d0	        ;remember to clear d0.
        jsr     paintbit

;       redraw the right vertical edge of the pulldownmenu

        move.l  (sp),d0	        ;restore the width
        move.l  4(sp),d1        ;restore the heigth
        add.l   d0,a1	        ;point the pixel address to the top edge of the right side
        subq    #1,a1	        ;adjust address to point to byte with actual right edge
        clr.l   d0	        ;remember to clear d0 on call.
        clr.l   d2	        ;set bit

        jsr     paintbit

        movem.l (sp)+,d0-d1/a1  ;restore the parameters

        rts

;______________________________________________________________________
;
;  MAKEMENU
;	        Displays pull down menu when called.  Also makes
;	        entries in active rectangle table for each entry.
;
;  Inputs:  A1 = starting pixel address for menu "box"
;	    A2 = starting pixel address for menu option message
;	    A3 = ptr to menu strings
;	    A4 = ptr to menu id's
;	    D0 = menu "box" width
;	    D1 = menu "box" heigth
;	    D4 = # of menu entries
;
;______________________________________________________________________

MAKEMENU
        MOVEM.L D0-D3/A0,-(SP)

        .IF  BMENU = 0
        BSR     MAKEBOX	        ;go make menu "box"
        .ENDC

        MULU    #8,D0	        ;convert width to pixel count
        LEA     RectTable,A0    ;get ptr to active rectangle table
        MOVE    (A0)+,D1        ;get rectangle count
        CLR.L   D2	        ;clear for use
        MOVE.L  #MENUSPC,D3     ;space between menu entries

@1      ADDQ    #1,D1	        ;incr rectangle count
        MOVE.B  (A4)+,D2        ;get menu entry id
        MOVE    D2,(A0)+        ;save in table
        BSR.S   GETROWCOL       ;convert address to X,Y coordinates
        MULU    #8,D6	        ;convert to pixels
        MOVE    D6,(A0)+        ;save upper X coordinate
        MOVE    D5,(A0)+        ;save upper Y coordinate
        ADD     D0,D6	        ;compute and save
        MOVE    D6,(A0)+        ;  lower X coordinate
        ADD     #MENUSPC/90,D5  ;compute and save
        MOVE    D5,(A0)+        ; lower Y coordinate

        MOVE.L  A1,-(SP)        ;save "box" address
        MOVE.L  A2,A1	        ;get address for menu message
        BSR.S   GETROWCOL       ;compute msg output pt
        BSR     DSPMSG	        ;do display
        MOVE.L  (SP)+,A1        ;restore address for box
        ADD.L   D3,A1	        ;incr to next start pt for rectangle
        ADD.L   D3,A2	        ;also incr message address

        SUBQ    #1,D4	        ;loop until done
        BNE.S   @1

        MOVE    D1,RectCnt      ;save new rectangle count
        MOVEM.L (SP)+,D0-D3/A0  ;restore regs and exit
        RTS

;______________________________________________________________________
;
;       routine writetitle --> writes the title for the window whose
;			       left top corner is addressed by a1,
;			       whose width is indicated by d0.
;
;	  To arrive at the correct address to write the title string,
;	  the window width and string length must be divided by 2, the
;	  result of the string division is subtracted from the width
;	  division to arrive at the general byte column position to
;	  begin writing the title.
;
;
;	        inputs:	        d0=window width
;			        a1=window left/top corner point as a
;				   0..32670 screen offset address.
;			        a3=title string address
;
;	        output:	        all registers used are restored.
;______________________________________________________________________


WRITETITLE
        movem.l d0-d6/a0-a6,-(sp)       ;save as many registers as possible
        bsr.s   getlength	        ;calculate the length of the string

        lsr.l   #1,d0			   ;divide window width
        lsr.l   #1,d2			   ;divide string length
        sub.l   d2,d0		        ;1/2 width - 1/2 length --->d0

        bsr.s   getrowcol	        ;get the row and column coordinate of
                                        ;the window corner point
        addq    #4,d5		        ;adjust for 4 pixel rows
        add.l   d0,d6		        ;adjust column pointer

        movem.l d5/d6,-(sp)	        ;stack line/column pointers for later ref

        bsr     dspmsg

        movem.l (sp)+,d5/d6	        ;restore the parameters
        subq    #4,d5		        ;reduce the pixel pointer by 4
        subq    #2,d6		        ;backspace the column pointer by 2
        andi.w  #$FFFE,d6	        ;round off to nearest word
        sub.l   a6,a6		        ;clear a6
        bsr     setcrsr2	        ;convert standard row/col to pixel offset
        move.l  a6,a1		        ;move to a1
;
;       restore the string pointer so that its length can be recalculated.
;
        move.l  40(sp),a3
        bsr     getlength	        ;the length is returned in a2 and d2
        addq    #1,d2		        ;must round off the length to a word boundary
        andi.w  #$FFFE,d2
        move.l  d2,d0		        ;set width of inverted window to length..
        addq    #4,d0		        ;..of string plus 4
        moveq   #15,d1		        ;set the heigth of the window
        moveq   #-1,d2		        ;set the mask
        bsr     inverse		        ;invert the title

        movem.l (sp)+,d0-d6/a0-a6

        rts

;______________________________________________________________________
;
;       routine getrowcol --> converts a screen address displacement
;			      to row and column coordinates.
;
;	        inputs:	      a1=screen address in the range 0..32759
;	        outputs:      d5 set to row
;			      d6 set to byte col (the remainder)
;
;       registers used: d2 (but saved and restored)
;       registers destroyed: d5,d6 (set to new values)
;______________________________________________________________________

GETROWCOL
        move.l  d2,-(sp)        ;save d2
        move.l  a1,d2	        ;move the address to d2
        divu    #ROWBYTES,d2    ;divide the address by 90 bytes
        move    d2,d5	        ;new row
        swap    d2
        move.w  d2,d6	        ;remainder is column

;	 MOVE.L	 A1,D2		 ;now calculate row
;	 SUBI.L	 #TOPOFFSET,D2	 ;decr for offset
;	 DIVU	 #RBYTES,D2	 ;divide by bytes per char row
;	 MOVE	 D2,D5
;	 ADDQ	 #1,D5		 ;incr to next row

        move.l  (sp)+,d2        ;restore d2
        rts		        ;return

;______________________________________________________________________
;
;       routine getlength --> returns a value which is the length of
;			      the string referenced by a3.  The
;			      string is assumed to be terminated by
;			      the null character value.
;
;	        inputs:	      a3=string address
;	        outputs:      d2,a2: string length
;
;       registers destroyed: d2,a2 (set to new values)
;______________________________________________________________________

GETLENGTH
        move.l  a3,a2
@1      move.b  (a2)+,d2        ;read a byte
        bne.s   @1	        ;continue
        sub.l   a3,a2	        ;subtract the beginning from the end.
        move.l  a2,d2	        ;move it to d2 for reference
        rts		        ;return

;---------------------------------------------------------------------
;
;  Routine to display uncompressed icon.		        CHG008
;
; INPUTS:
;       A2 = pointer to uncompressed icon  (48 x 32 bitmap)
;       A6 = pointer to (even!) screen address for upper left hand
;	     corner of icon
; SIDE EFFECTS:
;       D0-D1 are trashed
;---------------------------------------------------------------------

DSPRGICON
        MOVEQ   #ICONWIDTH-1,D0 ;set default width	        CHG008
        MOVEQ   #ICONHIGH-1,D1  ; and heigth		        CHG008
        BSR.S   OUTPUT	        ;and do display		        CHG008
        RTS		        ;			        CHG008

;______________________________________________________________________
;
;  Subroutine to display message or icon.
;
;       The calling routine must provide the pointer to the raw bit map.
;
;       Call:   load d0 with number of bytes - 1 in the x axis
;	        load d1 with the number of pixels - 1 in the y axis
;
;	        lea  sourcebytes,a2
;	        lea  destination,a6
;	        jsr or bsr output
;
;       Returns with d6 updated.
;
;----------------------------------------------------------------------

OUTPUT
        MOVEM.L D2-D4/A6,-(SP)  ;save regs
        moveq   #90,d3

loop0   clr.l   d4
        move.w  d0,d2
        bra.s   loop2

loop1   addq    #1,d4

loop2   move.b  (a2)+,0(a6,d4)
        dbf     d2,loop1

        add.l   d3,a6
        dbf     d1,loop0
        addq    #1,d6

        MOVEM.L (SP)+,D2-D4/A6  ;restore
        rts

        .PAGE
;---------------------------------------------------------------------
;
;  Routine to display error icon with id #.
;
; INPUTS:
;       D1 = id # to display
;       A2 = pointer to compressed icon
;       A5 = upper left corner address for icon as
;	     offset from screen address
;
; SIDE EFFECTS:
;       D5-D6 are trashed
;---------------------------------------------------------------------

DSPNUMICON
        BSR     DSPALRTICON     ;display the icon
        MOVE    #ERRSTRT,A5     ;get icon address offset
        BSR.S   DSPNUM	        ;display id # on icon
        ADD.L   SCRNBASE,A5     ;get screen address
        BSR     DSPBAD	        ;display bad mark over icon
        RTS

;---------------------------------------------------------------------
;
;  Routine to display icon id #.
;
; INPUTS:
;       D1 = id # to display
;       A2 = pointer to compressed icon
;       A5 = upper left corner address for icon as
;	     offset from screen address
;
; SIDE EFFECTS:
;       D1/D5-D6/A2-A3 are trashed
;---------------------------------------------------------------------

DSPNUM  MOVE.L  D0,-(SP)        ;save reg
        MOVE.L  A5,A1	        ;convert icon address to row, col
        BSR     GETROWCOL

        LEA     XCARD,A3        ;slot card icon?
        CMPA.L  A2,A3
        BNE.S   @1	        ;skip if not
        ADD     #SLOTROW,D5     ;add offsets for card id to cursor ptrs
        ADDQ    #SLOTCOL,D6
        BRA.S   @6

@1      LEA     MEMBRD,A3       ;memory board?
        CMPA.L  A2,A3	        ;
        BNE.S   @2	        ;skip if not
        ADD     #MEMROW,D5      ;add offsets for card id
        ADDQ    #MEMCOL,D6
        BRA.S   @6	        ;and go display

@2      TST.B   SYSTYPE	        ;Lisa 2 system?		        CHG009
        BNE.S   @99	        ;exit if yes - no id #'s        CHG009

        LEA     DISKETTE,A3     ;diskette icon?
        CMPA.L  A2,A3
        BNE.S   @3
        ADD     #DISKROW,D5     ;compute posn for id #
        ADDQ    #DISKCOL,D6
        BRA.S   @6

@3      LEA     DRIVEN,A3       ;drive icon?		        CHG009
        CMPA.L  A2,A3	        ;			        CHG009
        BNE.S   @4	        ;skip if not		        CHG009
        ADDQ    #DRVROW,D5      ;add offsets for id #	        CHG009
        ADDQ    #DRVCOL,D6      ;			        CHG009
        BRA.S   @6	        ;and go display		        CHG009

@4
        SUBQ    #INSRTROW,D5    ;must be insert icon	        CHG009/CHG024
        ADDQ    #INSRTCOL,D6    ;			        CHG009

@6      BSR     SETCRSR	        ;get screen address in A6
        SUBQ    #1,D1	        ;check number to display
        BNE.S   @7
        LEA     ONE,A2	        ;set ptr to # icon
        BRA.S   @9

@7      SUBQ    #1,D1	        ;is it 2?
        BNE.S   @8
        LEA     TWO,A2
        BRA.S   @9

@8      LEA     THREE,A2        ;must be 3

@9      MOVEQ   #0,D0	        ;set width - 1
        MOVEQ   #4,D1	        ;and heigth - 1
        BSR.S   OUTPUT	        ;display it

@99     MOVE.L  (SP)+,D0        ;restore reg
        RTS		        ;and exit

;---------------------------------------------------------------------
;
;  Routine to display error icon.
;
; INPUTS:
;       A2 = pointer to compressed icon
;
; SIDE EFFECTS:
;       A2/A6, D5-D6 are trashed
;---------------------------------------------------------------------

DSPERRICON
        BSR     MAKEALERT       ;open alert box
        MOVEQ   #ERRROW,D5      ;set screen ptrs
        MOVEQ   #ERRCOL,D6
        BSR     SETCRSR	        ;get screen address in A6
        MOVE.L  A6,A5	        ;save it
        BSR     DSPICON	        ;go do display of component icon
DSPBAD
        LEA     CHECKMRK,A2     ;get ptr to check icon
        BSR.S   MRGICON	        ;do the merge
        LEA     BADMRK,A2       ;get ptr to slash icon
        BSR.S   MRGICON	        ;merge it
        RTS		        ;and exit


;---------------------------------------------------------------------
;
;  Routine to merge two icons, one over the other.
;
; INPUTS:
;       A2 = ptr to icon to be merged
;       A5 = pointer to base icon
;
; SIDE EFFECTS:
;       None
;---------------------------------------------------------------------

MRGICON MOVEM.L D0-D3/A5-A6,-(SP) ;save regs
        MOVE.L  A5,A6	        ;get start address
        ADDQ    #6,A6	        ;first display new icon next to other icon
        MOVEM.L A5-A6,-(SP)     ;save ptrs
        BSR     DSPICON
        MOVEM.L (SP)+,A5-A6     ;restore ptrs

        MOVEQ   #ROWBYTES-6,D3  ;set up row offset constant
        MOVEQ   #32-1,D2        ;icon heigth in pixel lines - 1
@1      MOVEQ   #3-1,D1	        ;icon width in words - 1
@2      MOVE    (A6),D0	        ;get from byte
        OR      D0,(A5)+        ;do the merge
        CLR     (A6)+	        ;erase the old
        DBF     D1,@2	        ;do full row
        ADDA.L  D3,A5	        ;bump ptrs to next row
        ADDA.L  D3,A6
        DBF     D2,@1	        ;go to next row

        MOVEM.L (SP)+,D0-D3/A5-A6 ;restore and exit
        RTS

;---------------------------------------------------------------------
;
;  Routine to display alert icon.
;
; INPUTS:
;       A2 = pointer to icon
;	     MSB set if uncompressed icon, else compressed assumed      CHG008
;
; SIDE EFFECTS:
;       A6, D5-D6 are trashed
;---------------------------------------------------------------------

DSPALRTICON
        MOVEM.L D0-D1/A2,-(SP)  ;save regs			        CHG008
        BSR     MAKEALERT       ;open alert box
        MOVEQ   #ALRTROW,D5     ;set screen ptrs
        MOVEQ   #ALRTCOL,D6
        BSR     SETCRSR	        ;get screen address in A6
        MOVE.L  A2,D1	        ;check icon address		        CHG008
        BPL.S   @1	        ;skip if for compressed icon	        CHG008
        BCLR    #31,D1	        ;clear indicator bit		        CHG008
        MOVE.L  D1,A2	        ;and restore ptr		        CHG008
        BSR     DSPRGICON       ;display an uncompressed icon	        CHG008
        BRA.S   @2	        ;skip to exit			        CHG008
@1      BSR     DSPICON	        ;go do display			        CHG008
@2      MOVEM.L (SP)+,D0-D1/A2  ;restore regs			        CHG008
        RTS		        ;				        CHG008

;---------------------------------------------------------------------
;
;  Routine to display icon with question mark along side.
;
; INPUTS:
;       A2 = pointer to compressed icon
; OUTPUTS:
;       A5 = icon screen address
; SIDE EFFECTS:
;       A2/A6, D5-D6 are trashed
;---------------------------------------------------------------------

DSPQICON
        BSR     MAKEALERT       ;open alert box
        MOVEQ   #ERRROW,D5      ;set screen ptrs
        MOVEQ   #ERRCOL,D6
        BSR     SETCRSR	        ;get screen address in A6
        MOVE.L  A6,A5	        ;save it
        BSR.S   DSPICON	        ;go do display of component icon
        LEA     QUESTION,A2     ;get ptr to ? icon
        MOVE.L  A5,A6	        ;restore start address
        ADDA    #6,A6	        ;display next to component	        RM000
        BSR.S   DSPICON
        RTS

;---------------------------------------------------------------------
;
;  Routine to hilite (invert) a test icon.
;
; INPUTS:
;       A1 = address of icon
;
; SIDE EFFECTS:
;       None
;---------------------------------------------------------------------

INVICON MOVEM.L D0-D2,-(SP)     ;save regs
        MOVEQ   #ICONWIDTH,D0   ;set parms for icon
        MOVEQ   #ICONHIGH,D1
        MOVEQ   #-1,D2	        ;set fill pattern
        BSR     INVERSE	        ;and go invert selected one
        MOVEM.L (SP)+,D0-D2     ;restore
        RTS

;---------------------------------------------------------------------
;
;  Routine to display test icons.
;
; INPUTS:
;       None
;
; SIDE EFFECTS:
;       A2/A6 trashed
;---------------------------------------------------------------------

DSPCPU
        LEA     CPUBRD,A2       ;set ptr for CPU board icon
        MOVEA   #CPUSTRT,A6     ;and address
        BRA.S   DODSPLY	        ;go do display

DSPMBRD
        LEA     MEMBRD,A2       ;set ptr for Memory board icon
        MOVEA   #MEMSTRT,A6     ;and address
        BRA.S   DODSPLY	        ;go do display

DSPIOB
        LEA     IOBRD,A2        ;set ptr for I/O board icon
        MOVEA   #IOSTRT,A6      ;and address
        BRA.S   DODSPLY	        ;go do display

DSPXCRD
        LEA     XCARD,A2        ;set ptr for I/O slot card icon
        MOVEA   #XCRDSTRT,A6    ;and address

DODSPLY
        ADDA.L  SCRNBASE,A6     ;compute screen address for display
        BSR.S   DSPICON	        ;go do display
        RTS

;---------------------------------------------------------------------
;
;  Routine to display icon with check mark.
;
;  Inputs:
;       None
;  Outputs:
;       None
; Side Effects:
;       A6 trashed
;---------------------------------------------------------------------

CHKCPU
        BSR.S   DSPCPU	        ;redisplay CPU icon
        MOVEA   #CPUSTRT,A5     ;get start address for it
        BRA.S   DSPCHECK        ;and go add check mark

CHKMBRD
        BSR.S   DSPMBRD	        ;redisplay Memory board icon
        MOVEA   #MEMSTRT,A5     ;get start address for it
        BRA.S   DSPCHECK        ;and go add check mark

CHKIOBRD
        BSR.S   DSPIOB	        ;redisplay I/O icon
        MOVEA   #IOSTRT,A5      ;get start address for it
        BRA.S   DSPCHECK        ;and go add check mark

CHKXCRD
        BSR.S   DSPXCRD	        ;redisplay I/O slot card icon
        MOVEA   #XCRDSTRT,A5    ;get start address for it

DSPCHECK
        LEA     CHECKMRK,A2     ;get ptr to check icon
        ADDA.L  SCRNBASE,A5     ;compute screen address for display
        BSR     MRGICON	        ;and go do merge
        RTS

;---------------------------------------------------------------------
;
;  Routine to display compressed icon.
;
; INPUTS:
;       A2 = pointer to compressed icon
;       A6 = pointer to (even!) screen address for upper left hand
;	     corner of icon
; SIDE EFFECTS:
;       A6 is trashed
;---------------------------------------------------------------------

DSPICON
        MOVEM.L D0-D2/A0/A2,-(SP)       ;			        CHG009
        MOVE.L  A6,A0		        ; save screen start address

        MOVEQ   #23,D1		        ; There are 24 octals in an icon
        MOVEQ   #5,D2		        ; reset row bytes counter

DLOOP   MOVE    #$100,D0	        ; prime D0 for 8 bit count count
        MOVE.B  (A2)+,D0	        ; load map byte from compressed image

MLOOP   LSR.W   #1,D0		        ; shift off map bit
        BEQ.S   DONE		        ; byte done when = 0
        BCC.S   BLACK		        ; dispatch on the bit
        CLR.B   (A6)+		        ; store zero in new
        BRA.S   CHECK		        ; continue for all 8 bits
BLACK   MOVE.B  (A2)+,(A6)+	        ; store byte in new

CHECK   DBF     D2,MLOOP	        ; see if on scanline seam(every 6 bytes)
        ADDA    #90-6,A6	        ; bump to next scanline	        RM015
        MOVEQ   #5,D2		        ; reset row bytes counter
        BRA.S   MLOOP		        ; continue for all 8 bits

DONE    DBF     D1,DLOOP	        ; do the rest of the octals in ICON

; Now unXOR the icon on the screen

        MOVE.L  A0,A6		        ; get screen pointer saved above
        MOVE.L  A6,A2		        ; second pointer
        ADDA    #90,A2		        ; scanline pointer	        RM015

        MOVE    #30,D1		        ; do 31 scanlines

; This is the cause of the even destination restriction

XLOOP   MOVE.L  (A6)+,D0	        ; get long from previous scanline
        EOR.L   D0,(A2)+	        ; xor into this scanline
        MOVE.W  (A6)+,D0	        ; get word from previous scanline
        EOR.W   D0,(A2)+	        ; xor into this scanline
        ADDA    #90-6,A2	        ; next scan line + rowbytes     RM015
        ADDA    #90-6,A6	        ; next scan line + rowbytes     RM015

        DBF     D1,XLOOP

        MOVEM.L (SP)+,D0-D2/A0/A2       ;			        CHG009
        RTS

        .PAGE

;----------------------------------------------------------------------
;  Subroutine to display text string according to keyboard id
;  Inputs:
;       A3 = ptr to message
;       D1 = nonzero if '...' string to be appended
;  Outputs:
;       A2 = ptr to start of string
;       A3 = ptr to end of string
;  Side Effects:
;       D5-D6, A3 trashed
;----------------------------------------------------------------------

DSPSTRING
        MOVEM.L D0/D2,-(SP)     ;save regs
        LEA     MENUHDG,A2      ;don't translate service mode messages
        CMPA.L  A2,A3
        BEQ.S   DSPOUT	        ;skip if it is
        MOVE.L  A3,A2	        ;else save starting point
        MOVE.B  KEYID,D0        ;get keyboard id
        BEQ.S   DSPOUT	        ;skip if no id available
        ANDI.B  #$3F,D0	        ;clear mfg code
        MOVE.B  D0,D2	        ;move to working reg

;  Search for US, UK or Canadian keyboard

        ANDI.B  #$F0,D2	        ;old US keyboard?
        BEQ.S   DSPOUT	        ;yes - go do English display
        CMPI.B  #$30,D2	        ;US or Canadian layout?
        BNE.S   @1
        CMPI.B  #$3D,D0	        ;Canadian?
        BEQ.S   DSPALL	        ;yes - display all languages
        BRA.S   DSPOUT	        ;else just English

@1      CMPI.B  #$20,D2	        ;European keyboard?
        BNE.S   DSPALL	        ;no - display all languages
        CMPI.B  #$2F,D0	        ;UK?
        BEQ.S   DSPOUT	        ;yes - display English

;  Search for German type keyboard

        CMPI.B  #$2E,D0	        ;German?
        BEQ.S   DSPGERMN
        CMPI.B  #$26,D0	        ;Swiss-German?
        BEQ.S   DSPGERMN

;  Search for French type keyboard

        CMPI.B  #$2D,D0	        ;French?
        BEQ.S   DSPFRNCH
        CMPI.B  #$27,D0	        ;Swiss-French?
        BEQ.S   DSPFRNCH

;  Display all languages for any other keyboard (e.g., Italian, Spanish, etc.)

DSPALL  BTST    #MENU,STATFLGS  ;doing menu?
        BNE.S   @1	        ;skip if yes
        SUB     #CHRSPC,D5      ;back up one row
        BSR.S   DSPIT	        ;display English string
        ADD     #CHRSPC,D5      ;incr to next row
        BSR.S   DSPIT	        ;display French translation
        ADD     #CHRSPC,D5      ;bump another row
        BRA.S   DSPOUT	        ;go do final display of German

@1      BSR.S   DSPMSLSH        ;display English followed by /
        BSR.S   DSPMSLSH        ;display French followed by /
        BRA.S   DSPOUT	        ;and go do final German display

DSPGERMN
        TST.B   (A3)+	        ;skip two strings before output
        BNE.S   DSPGERMN

DSPFRNCH
        TST.B   (A3)+	        ;skip one string before output
        BNE.S   DSPFRNCH
        MOVE.L  A3,A2	        ;save new beginning ptr

DSPOUT  BSR.S   DSPIT	        ;do display
        MOVEM.L (SP)+,D0/D2     ;restore regs
        RTS		        ; and exit


;----------------------------------------------------------------------
;  Subroutine to display text string followed by '...'
;  Inputs:
;       A3 = ptr to message
;       D1 = nonzero if '...' string to be appended
;  Outputs:
;       None
;  Side Effects:
;       A3 updated to next location after 0 byte
;----------------------------------------------------------------------

DSPIT   MOVEM.L D5-D6,-(SP)     ;save cursor ptrs
        BSR.S   DSPMSG	        ;output message
        MOVE.L  A3,-(SP)        ;save msg ptr
        TST     D1	        ;check if periods needed
        BEQ.S   @9	        ;skip if not
        LEA     PERIODS,A3      ;else do display
        BSR.S   DSPMSG
@9
        MOVE.L  (SP)+,A3        ;restore regs and exit
        MOVEM.L (SP)+,D5-D6
        RTS


;----------------------------------------------------------------------
;  Subroutine to display text string followed by '/'
;  Inputs:
;       A3 = ptr to message
;  Outputs:
;       None
;  Side Effects:
;       A3 updated to next location after 0 byte
;----------------------------------------------------------------------

DSPMSLSH
        BSR.S   DSPMSG	        ;output message
        MOVEQ   #'/',D0	        ;display /
        BSR.S   DSPVAL
        RTS

;----------------------------------------------------------------------
;  Subroutine to display alert box message
;  Inputs:
;       A3 = ptr to message
;  Outputs:
;       None
;----------------------------------------------------------------------

DSPALRTMSG
        MOVEM.L D4-D6,-(SP)     ;save regs			        CHG005
        MOVE    #MSGROW,D5      ;set screen ptrs
        MOVEQ   #MSGCOL,D6
        MOVE    D5,D4	        ;set left margin in case of CR	        CHG005
        BSR.S   DSPMSG	        ;go do display
        MOVEM.L (SP)+,D4-D6     ;restore regs			        CHG005
        RTS

;----------------------------------------------------------------------
;  Routine to convert row coordinate to pixel row coordinate before
;  doing message display
;
;  Expects D5 = row coordinate from 0-32
;----------------------------------------------------------------------

CONVRTD5
        MULU    #10,D5		        ;multiply by pixel lines per char row
        BSR.S   DSPMSG		        ;then go do message
        RTS

        .ENDC			        ;{USERINT}

;----------------------------------------------------------------------
;  Subroutine to display message followed by a line feed, CR.
;  Calls DSPMSG routine, with same assumptions as that routine.
;----------------------------------------------------------------------

DSPMSGR BSR.S   DSPMSG	        ;go display msg

        .IF USERINT = 0
        ADDQ    #1,D5	        ;do "line feed"
        .ELSE
        ADD     #CHRSPC,D5      ;do "line feed"
        .ENDC

        MOVEQ   #1,D6	        ;and "carriage return"
        RTS

;---------------------------------------------------------------------------
; Subroutine to display message on screen.
; Requires inputs:
;       A3 - ptr to ASCII character string ended by 0 byte
;       D4 = left margin if message has a CR
;       D5 = cursor row position (0 - 32 decimal)
;       D6 = cursor column position (1 - 88 decimal)
; Uses regs:
;       D0 - for character to display
;
; NOTE: ONLY UPPER CASE ALPHA, NUMERIC AND CERTAIN SPECIAL CHARS SUPPORTED!
;---------------------------------------------------------------------------

DSPMSG  MOVE.L  D0,-(SP)	        ;save reg

        .IF     ROM4K = 0
@1      CMPI    #LASTROW,D5	        ;check if out of bounds
        BLE.S   @2		        ;skip if OK
        BSR     SCROLL		        ;else scroll page
        .ENDC

@2      CLR.L   D0		        ;clear for use
        MOVE.B  (A3)+,D0	        ;get a char to display
        BEQ.S   DSPDONE		        ;exit if done
        BSR.S   DSPVAL		        ;go do display
        BRA.S   @1		        ;continue until done
DSPDONE MOVE.L  (SP)+,D0	        ;restore and exit
        RTS

        .PAGE
;----------------------------------------------------------------------
; Subroutine to set cursor position in video page for message display.
; Requires inputs:
;       D5 = row position (0 - 32 decimal)
;       D6 = column position (1 - 88 decimal)
;       location SCRNBASE = base address for video page
; Provides output:
;       A6 = address for new cursor location
;----------------------------------------------------------------------

SETCRSR
        MOVE.L  SCRNBASE,A6	        ;get base address for screen
SETCRSR2
        MOVE.L  D0,-(SP)	        ;save reg
        CLR.L   D0		        ;use as working reg

        .IF  USERINT = 0
        MOVE.B  D5,D0		        ;get row coordinate
        .ELSE
        MOVE    D5,D0		        ;get pixel row
        .ENDC

        MULU    #RBYTES,D0	        ;compute byte offset

;	 .IF  USERINT = 0
        ADD     #RBYTES,D0	        ;add one more
;	 .ELSE
;	 ADD	 #TOPOFFSET,D0		 ;adjust for offset from top of screen
;	 .ENDC

        ADD.L   A6,D0		        ;add in base screen address
        MOVE.L  D0,A6		        ;and save new value
        CLR.L   D0

        .IF  USERINT = 0
        MOVE.B  D6,D0		        ;get col coordinate
        .ELSE
        MOVE    D6,D0		        ;get pixel col
        .ENDC

        ADDA.L  D0,A6		        ;add to cursor address
        MOVE.L  (SP)+,D0	        ;restore and exit
        RTS

;------------------------------------------------------------------------
; Subroutine to display single ASCII character.
; Requires input:
;       D0 = character to display
;       D4 = left margin if CR char
;       D5 = cursor row position (0 - 32 decimal)
;       D6 = cursor column position (1 - 88 decimal)
; Returns output:
;       D6 = new cursor col position (incremented by 1)
;------------------------------------------------------------------------

DSPVAL  MOVEM.L A2/A6/D0-D1,-(SP)       ;save regs
        BSR.S   SETCRSR		        ;set cursor position
        ANDI    #$7F,D0		        ;ensure valid

        .IF  USERINT = 1
        TST.B   D0		        ;apple icon?
        BEQ.S   @4
        .ENDC

        .IF  ROM4K = 0
        CMPI.B  #$20,D0		        ;space?
        BEQ.S   @3		        ;skip if yes
        CMPI.B  #RET,D0		        ;carriage return?
        BEQ.S   @5		        ;skip if yes
        CMPI.B  #QUESTN,D0	        ;'?' char?
        BEQ.S   @6

        SUB.B   #$2D,D0		        ;else check if in table
        BLT.S   @1
        CMPI.B  #$C,D0		        ;numeric char?
        BLE.S   @2		        ;skip if yes
        SUB.B   #7,D0		        ;else decr for alpha check
        CMPI.B  #$D,D0		        ;check if in alpha range
        BLT.S   @1		        ;skip if invalid
        CMPI.B  #$26,D0		        ;last valid char = 'Z'
        BLE.S   @2
                              ;skip if OK
        .ELSE
        SUB.B   #$30,D0		        ;convert to table index
        BMI.S   @3		        ;skip if space
        CMP.B   #$11,D0		        ;alpha char?
        BLT.S   @2		        ;skip if not
        SUB.B   #$7,D0		        ;else do further conversion
        BRA.S   @2		        ;and go do output
        .ENDC

        .IF  USERINT = 0
@1      LEA     INVCHAR,A2	        ;else set for invalid character
        BRA.S   OUTPUT

@3      LEA     SPACE,A2	        ;set ptr to space char
        BRA.S   OUTPUT

@5      ADD     #CHRSPC,D5	        ;set cursor for next row
        MOVE    D4,D6		        ;set to left margin
        BRA.S   DSPVXIT

@2      LSL     #3,D0		        ;convert for table
        LEA     FONTTBL(D0),A2	        ;get ptr to char in table
OUTPUT  MOVE.B  (A2)+,(A6)	        ;output bits
        MOVE.B  (A2)+,R1(A6)
        MOVE.B  (A2)+,R2(A6)
        MOVE.B  (A2)+,R3(A6)
        MOVE.B  (A2)+,R4(A6)
        MOVE.B  (A2)+,R5(A6)
        MOVE.B  (A2)+,R6(A6)
        MOVE.B  (A2)+,R7(A6)
        ADDQ    #1,D6		        ;bump cursor col coordinate

        .ELSE

@1      LEA     INVCHAR,A2	        ;else set for invalid character
        BRA.S   OUT

@3      LEA     SPACE,A2	        ;set ptr to space char
        BRA.S   OUT

@4      LEA     APPLICON,A2	        ; display apple icon
        BRA.S   OUT

@5      ADD     #CHRSPC,D5	        ;set cursor for next row
        MOVE    D4,D6		        ;set to left margin
        BRA.S   DSPVXIT

@6      LEA     QUESTCH,A2	        ;set ptr to '?' char
        BRA.S   OUT

@2      MOVE    D0,D1		        ;convert for table (multiply by 6)  CHG017
        LSL     #3,D0		        ;mult by 8
        SUB     D1,D0		        ; then subtract twice
        SUB     D1,D0		        ;				    CHG017

        LEA     FONTTBL(D0),A2	        ;get ptr to char in table

out     clr.l   d0		        ;set number of bytes-1 in x direction
        moveq   #5,d1		        ;set number of pixels-1 in y direction  CHG017
        MOVE.B  #0,R0(A6)	        ;first line always 0		        CHG017
        ADDA.L  #RBYTES,A6	        ;bump ptr to next row		        CHG017
        bsr     output		        ;output char
        MOVE.B  #0,R7(A6)	        ;and add final 0 byte
        .ENDC

DSPVXIT
        MOVEM.L (SP)+,A2/A6/D0-D1       ;restore and exit
        RTS

        .IF     EXTERNAL = 1
        .NOLIST
        .ENDC
        .PAGE
;----------------------------------------------------------------------
; CHARACTER FONT TABLE
;----------------------------------------------------------------------
SPACE
    .BYTE    $00,$00,$00,$00,$00,$00   ;  (space)

FONTTBL

  .IF  ROM4K = 0
    .BYTE    $00,$00,$00,$7C,$00,$00   ; code =	 45 '-'
    .BYTE    $00,$00,$00,$00,$00,$30   ; code =	 46 '.'
    .BYTE    $04,$08,$10,$20,$40,$80   ; code =	 47 '/'
  .ENDC

    .BYTE    $38,$44,$44,$44,$44,$38   ; code =	 48 '0'
    .BYTE    $08,$38,$08,$08,$08,$08   ; code =	 49 '1'
    .BYTE    $38,$44,$08,$10,$20,$7C   ; code =	 50 '2'
    .BYTE    $38,$44,$18,$04,$44,$38   ; code =	 51 '3'
    .BYTE    $08,$18,$28,$48,$7C,$08   ; code =	 52 '4'
    .BYTE    $7C,$40,$78,$04,$44,$38   ; code =	 53 '5'
    .BYTE    $38,$40,$78,$44,$44,$38   ; code =	 54 '6'
    .BYTE    $7C,$08,$10,$10,$20,$20   ; code =	 55 '7'
    .BYTE    $38,$44,$38,$44,$44,$38   ; code =	 56 '8'
    .BYTE    $38,$44,$44,$3C,$04,$38   ; code =	 57 '9'

    .BYTE    $30,$48,$84,$FC,$84,$84   ; code =	 65 'A'
    .BYTE    $F8,$84,$F8,$84,$84,$F8   ; code =	 66 'B'
    .BYTE    $78,$84,$80,$80,$84,$78   ; code =	 67 'C'
    .BYTE    $F8,$84,$84,$84,$84,$F8   ; code =	 68 'D'
    .BYTE    $FC,$80,$F8,$80,$80,$FC   ; code =	 69 'E'
    .BYTE    $FC,$80,$F8,$80,$80,$80   ; code =	 70 'F'
    .BYTE    $78,$84,$80,$9C,$84,$7C   ; code =	 71 'G'
    .BYTE    $84,$84,$FC,$84,$84,$84   ; code =	 72 'H'
    .BYTE    $38,$10,$10,$10,$10,$38   ; code =	 73 'I'
    .BYTE    $1C,$08,$08,$08,$88,$70   ; code =	 74 'J'
    .BYTE    $88,$90,$A0,$D0,$88,$84   ; code =	 75 'K'
    .BYTE    $80,$80,$80,$80,$80,$FC   ; code =	 76 'L'
    .BYTE    $84,$CC,$B4,$84,$84,$84   ; code =	 77 'M'
    .BYTE    $84,$C4,$A4,$94,$8C,$84   ; code =	 78 'N'
    .BYTE    $78,$84,$84,$84,$84,$78   ; code =	 79 'O'
    .BYTE    $F8,$84,$84,$F8,$80,$80   ; code =	 80 'P'
    .BYTE    $78,$84,$84,$84,$94,$78   ; code =	 81 'Q'
    .BYTE    $F8,$84,$84,$F8,$88,$84   ; code =	 82 'R'
    .BYTE    $78,$84,$60,$18,$84,$78   ; code =	 83 'S'
    .BYTE    $FE,$10,$10,$10,$10,$10   ; code =	 84 'T'
    .BYTE    $84,$84,$84,$84,$84,$78   ; code =	 85 'U'
    .BYTE    $44,$44,$28,$28,$10,$10   ; code =	 86 'V'
    .BYTE    $82,$82,$92,$AA,$44,$44   ; code =	 87 'W'
    .BYTE    $44,$28,$10,$28,$44,$82   ; code =	 88 'X'
    .BYTE    $82,$44,$28,$10,$10,$10   ; code =	 89 'Y'
    .BYTE    $FC,$08,$10,$20,$40,$FC   ; code =	 90 'Z'

  .IF  ROM4K = 0
QUESTCH
    .BYTE    $38,$44,$08,$10,$00,$10   ; code =	 63 '?'
  .ENDC

INVCHAR
    .BYTE    $C7,$BB,$F7,$EF,$FF,$EF   ;  inverse of ?

        .IF  ROM4K = 0
APPLICON
    .BYTE    $08,$77,$FE,$FE,$7F,$3E   ; apple icon

        .PAGE
        .ALIGN 2
;----------------------------------------------------------------------
;  Keycode to Ascii Table  (assumes alpha-lock so upper case only)
;----------------------------------------------------------------------

AsciiTable					 ;				        RM000
 .BYTE	 $1B,$2D,$11,$12,$37,$38,$39,$14	 ;Pad : Clear - Left Right 789 Up
 .BYTE	 $34,$35,$36,$13,$2E,$32,$33,$03	 ;Pad : 456 Down .23 Enter
 .BYTE	 $00,$00,$00,$00,$00,$00,$00,$00	 ;unused
 .BYTE	 $00,$00,$00,$00,$00,$00,$00,$00	 ;unused
 .BYTE	 $2D,$3D,$00,$00,$50,$08,$00,$00	 ;- = 2*unused P BackSp 2*unused
 .BYTE	 $0D,$30,$00,$00,$2F,$31,$00,$00	 ;Ret Pad:0 2*unused / Pad:1 2*unused
 .BYTE	 $39,$30,$55,$49,$4A,$4B,$5B,$5D	 ;90UIJK[]
 .BYTE	 $4D,$4C,$3B,$27,$20,$2C,$2E,$4F	 ;ML;' Space ,.O
 .BYTE	 $45,$36,$37,$38,$35,$52,$54,$59	 ;E6785RTY
 .BYTE	 $00,$46,$47,$48,$56,$43,$42,$4E	 ;Option FGHVCBN
 .BYTE	 $41,$32,$33,$34,$31,$51,$53,$57	 ;A2341QSW
 .BYTE	 $00,$5A,$58,$44,$00,$00,$00,$00	 ;Tab ZXD unused Alpha Shift Cmd

        .ENDC
        .IF  USERINT = 1
;----------------------------------------------------------------------
;  Icons
;----------------------------------------------------------------------

CrsrData				        ;arrow for mouse cursor
CrsrMask				        ;same for mask
        .WORD   $8000,$C000,$E000,$F000
        .WORD   $F800,$FC00,$FE00,$FF00
        .WORD   $F800,$F800,$CC00,$8C00
        .WORD   $0600,$0600,$0300,$0300

ONE     .BYTE   $E0,$60,$60,$60,$F0	        ;icon id = 1
TWO     .BYTE   $E0,$30,$60,$C0,$F0	        ;icon id = 2
THREE   .BYTE   $E0,$30,$60,$30,$E0	        ;icon id = 3

IObrd	  .BYTE $FF,$FF,$FF,$3F,$03,$FF,$00,$FF
          .BYTE $FF,$FF,$E0,$01,$FF,$FF,$FF,$E4
          .BYTE $FF,$C0,$70,$2F,$F9,$50,$66,$9E
          .BYTE $C0,$01,$80,$F7,$03,$79,$56,$06
          .BYTE $74,$FE,$0F,$FF,$FF,$FF,$FF,$FF
          .BYTE $FF,$FF,$3F,$01,$AA,$60,$AA,$AF
          .BYTE $FF,$C0,$03,$07,$C4,$FF,$E0,$55
          .BYTE $55,$50,$F1,$FF,$FF,$F8,$FF,$FF

CPUbrd	  .BYTE $FF,$FF,$FF,$3F,$03,$FF,$00,$FF
          .BYTE $FF,$FF,$E0,$01,$FF,$FF,$FF,$C4
          .BYTE $FF,$C0,$79,$F2,$40,$F9,$38,$E0
          .BYTE $BF,$E0,$EF,$F0,$71,$38,$01,$80
          .BYTE $79,$FC,$03,$C0,$FF,$FF,$FF,$FF
          .BYTE $FF,$FF,$FF,$3F,$01,$FE,$C0,$AA
          .BYTE $AA,$BF,$C0,$03,$FC,$84,$1F,$E0
          .BYTE $01,$55,$55,$40,$E1,$03,$FF,$FF
          .BYTE $E0,$FF,$FF

MEMbrd	  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$C3,$1F
          .BYTE $FF,$FF,$C0,$80,$0F,$FF,$FF,$80
          .BYTE $07,$FF,$E0,$E3,$03,$FF,$F0,$FF
          .BYTE $FF,$FF,$71,$04,$5E,$88,$02,$1C
          .BYTE $8E,$50,$03,$8C,$70,$C7,$01,$0C
          .BYTE $20,$7B,$0E,$04,$0C,$5E,$88,$03
          .BYTE $FF,$D5,$57,$00,$FF,$80,$07,$FF
          .BYTE $80,$03,$FF,$C0,$F3,$2A,$A8,$FC
          .BYTE $7F,$FC,$FF,$FF,$FF,$FF

Xcard	  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$E1,$01
          .BYTE $FF,$FF,$80,$FC,$FF,$FF,$FF,$FF
          .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
          .BYTE $FF,$FF,$DF,$03,$63,$EA,$AD,$80
          .BYTE $01,$3C,$C0,$06,$15,$50,$CF,$3F
          .BYTE $F8

waiticon  .BYTE $FF,$FF,$FF,$61,$1F,$FF,$FF,$F8
          .BYTE $0F,$18,$FF,$FF,$F0,$0F,$FF,$FF
          .BYTE $86,$F0,$11,$FF,$FF,$88,$6D,$05
          .BYTE $A0,$02,$18,$80,$01,$40,$01,$4F
          .BYTE $F2,$CE,$80,$A8,$15,$F3,$54,$2A
          .BYTE $3C,$2A,$54,$14,$28,$CF,$08,$10
          .BYTE $FF,$3C,$08,$10,$14,$28,$CF,$28
          .BYTE $14,$F3,$50,$0A,$1C,$A0,$05,$01
          .BYTE $46,$62,$86,$80,$02,$88,$11,$40
          .BYTE $61,$05,$10,$08,$A0,$11,$18,$E0
          .BYTE $07,$88,$0F,$FF,$FF,$86,$F0,$0F
          .BYTE $FF,$FF,$F0,$E1,$1F,$FF,$FF,$F8
          .BYTE $FF,$FF

proicon	  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
          .BYTE $FF,$00,$1F,$FF,$FF,$FF,$FF,$F8
          .BYTE $3F,$FF,$F0,$FF,$FF,$FF,$FC,$FF
          .BYTE $CC,$03,$7F,$01,$80,$CF,$03,$7F
          .BYTE $FC,$01,$80,$00,$3F,$FF,$FF,$FF
          .BYTE $FF,$FC,$1C,$FF,$60,$FF,$F3,$FF
          .BYTE $38,$03,$0C,$FD,$C0,$FF,$FF,$FF
          .BYTE $FF,$FF,$FF

upper	  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF	        ;CHG024
          .BYTE $FF,$2F,$08,$1F,$FF,$08,$FF,$FC
          .BYTE $10,$1F,$FF,$FF,$FC,$02,$20,$1F
          .BYTE $FF,$FF,$FC,$47,$F8,$20,$1F,$FF
          .BYTE $FF,$FC,$80,$1F,$FF,$08,$FF,$FC
          .BYTE $80,$1F,$FF,$FF,$FC,$80,$47,$F8
          .BYTE $1F,$FF,$FF,$FC,$20,$E0,$1F,$FF
          .BYTE $FF,$FC,$10,$FB,$08,$FF,$FF,$FF
          .BYTE $FF,$FF,$FF,$FF

driven	  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF	        ;CHG024
          .BYTE $FF,$EF,$02,$38,$03,$FF,$04,$07
          .BYTE $FF,$22,$88,$3F,$FF,$F8,$11,$FE
          .BYTE $E8,$7F,$FF,$FC,$20,$8B,$20,$7F
          .BYTE $FF,$FC,$A0,$11,$FE,$3F,$FF,$F8
          .BYTE $08,$E3,$07,$FF,$84,$F8,$03,$FF
          .BYTE $02,$FF,$FF,$FF,$FF,$FF,$FF,$FF

insertd	  .BYTE $FF,$79,$07,$FE,$0F,$C6,$FF,$7F
          .BYTE $FF,$F0,$71,$FF,$FF,$F8,$0A,$18
          .BYTE $AA,$AA,$A8,$FA,$AA,$AA,$F6,$A0
          .BYTE $60,$E3,$03,$C0,$07,$38,$04,$20
          .BYTE $06,$08,$10,$FF,$F3,$08,$10,$3C
          .BYTE $04,$20,$03,$C0,$FF,$FF,$FF,$FF
          .BYTE $61,$1F,$FF,$FF,$F8,$0F,$38,$FF
          .BYTE $FF,$F0,$01,$80,$CF,$02,$40,$F3
          .BYTE $04,$20,$3C,$08,$10,$10,$08,$CF
          .BYTE $1C,$38,$FF,$FF,$CF,$03,$C0

keybdout  .BYTE $CF,$01,$C0,$FF,$3F,$0E,$38,$CF
          .BYTE $08,$08,$F3,$04,$10,$3C,$02,$20
          .BYTE $01,$40,$DF,$80,$F3,$01,$C0,$3F
          .BYTE $01,$40,$20,$1B,$6D,$B6,$DB,$60
          .BYTE $16,$DB,$08,$6D,$B6,$DF,$3B,$6D
          .BYTE $B6,$DB,$80,$67,$80,$06,$DB,$6D
          .BYTE $B6,$D8,$FF,$0F,$4F,$FF,$FF,$FF
          .BYTE $00,$FF,$F0,$FF,$FF,$FF,$FF,$FF
          .BYTE $F8,$00,$1B,$6D,$B6,$D8,$36,$C0
          .BYTE $1B,$6D,$00,$B6,$D8,$36,$C0,$1B
          .BYTE $6D,$B6,$D8,$00,$36,$C0,$1B,$6D
          .BYTE $B6,$D8,$36,$C0,$00,$1B,$6D,$B6
          .BYTE $D8,$36,$C0,$1B,$6D,$00,$B6,$D8
          .BYTE $36,$C0,$1B,$FF,$FF,$D8,$00,$36
          .BYTE $C0,$1B,$FF,$FF,$D8,$36,$C0,$00
          .BYTE $FF,$FF,$FF,$FF,$FF,$F8,$7F,$FF
          .BYTE $F0,$FF,$FF,$FF,$F0,$FF

mouseout  .BYTE $FD,$E0,$FF,$F3,$07,$1C,$3C,$04
          .BYTE $04,$02,$08,$CF,$01,$10,$F7,$A0
          .BYTE $3D,$40,$01,$E0,$FF,$F3,$01,$20
          .BYTE $7F,$3F,$9C,$FF,$80,$FF,$FE,$FF
          .BYTE $FF,$3C,$7E,$7C,$FF,$FE,$CF,$1F
          .BYTE $F0,$F3,$0F,$E0,$3C,$0F,$E0,$1F
          .BYTE $F0,$FF,$FF,$FF,$FF,$FF,$FF,$CF
          .BYTE $FF,$FE

Question  .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
          .BYTE $CF,$0F,$E0,$F3,$03,$80,$FE,$0C
          .BYTE $CF,$03,$80,$F7,$E0,$BF,$03,$EF
          .BYTE $03,$FF,$FE,$03,$FF,$FF,$FF,$FF
          .BYTE $FF,$FF,$FF

checkmrk  .BYTE $CF,$07,$80,$F3,$0E,$80,$BE,$1B
          .BYTE $36,$EF,$6C,$7B,$D8,$01,$9E,$B0
          .BYTE $03,$60,$E7,$06,$C0,$79,$0D,$80
          .BYTE $1B,$DF,$36,$F7,$6C,$3D,$D8,$01
          .BYTE $B0,$CF,$03,$60,$F3,$06,$C0,$BC
          .BYTE $0D,$80,$1B,$EF,$36,$FB,$6C,$9E
          .BYTE $D8,$01,$B0,$E7,$03,$60,$38,$F8
          .BYTE $06,$C0,$DC,$0D,$CE,$80,$36,$1B
          .BYTE $F3,$1B,$36,$3C,$0D,$EC,$06,$D8
          .BYTE $CF,$03,$30,$F3,$01,$E0

badmrk	  .BYTE $3C,$03,$C0,$02,$E0,$CF,$01,$B0
          .BYTE $F7,$D8,$7D,$6C,$36,$DF,$1B,$E7
          .BYTE $0D,$80,$79,$06,$C0,$03,$9E,$60
          .BYTE $01,$B0,$EF,$D8,$FB,$6C,$BE,$36
          .BYTE $1B,$CF,$0D,$80,$F3,$06,$C0,$3C
          .BYTE $03,$60,$01,$B0,$DF,$D8,$F7,$6C
          .BYTE $7D,$36,$1B,$9F,$0D,$80,$E7,$06
          .BYTE $C0,$79,$03,$60,$01,$BE,$B0,$D8
          .BYTE $EF,$6C,$FB,$36,$3E,$1B,$0E,$80

diskette  .BYTE $FF,$FF,$FF,$FF,$1F,$03,$FF,$FF
          .BYTE $86,$F8,$07,$FF,$FF,$F4,$EF,$0A
          .BYTE $FB,$05,$BC,$02,$80,$01,$FF,$7D
          .BYTE $78,$84,$CF,$01,$02,$FF,$7C,$01
          .BYTE $02,$84,$DF,$78,$FF,$FF,$FF,$7F
          .BYTE $07,$10,$FF,$FF,$FF,$80,$03,$FF
          .BYTE $FF,$FE,$FF,$FF,$FF,$FF

lisa	  .BYTE $FF,$0F,$03,$FF,$FF,$FF,$00,$FF
          .BYTE $C0,$07,$FF,$FF,$FF,$FF,$E0,$10
          .BYTE $0C,$FF,$FF,$F0,$30,$01,$FF,$70
          .BYTE $FF,$F8,$07,$80,$01,$9E,$FF,$01
          .BYTE $FF,$CF,$07,$80,$FF,$3F,$07,$80
          .BYTE $E7,$01,$FF,$09,$01,$FF,$01,$FF
          .BYTE $FF,$F8,$40,$07,$80,$0C,$FF,$FF
          .BYTE $F0,$30,$00,$07,$FF,$FF,$FF,$FF
          .BYTE $E0,$03,$FF,$00,$FF,$FF,$FF,$C0
          .BYTE $03,$FF,$FF,$FF,$00,$FF,$E0,$07
          .BYTE $FF,$FF,$FF,$FF,$F0,$61,$AA,$AA
          .BYTE $AA,$95,$FF,$18,$FF,$FF,$9F,$5F
          .BYTE $FF,$FD,$86,$1F,$0A,$AA,$A8,$15
          .BYTE $3F,$07,$FF,$00,$FF,$FF,$FF,$F0
          .BYTE $03,$FF,$FF,$FF,$FC,$FF,$E0,$FF
          .BYTE $FF,$FF

        .ENDC

        .PAGE
        .LIST
;----------------------------------------------------------------------
;  Message Table
;----------------------------------------------------------------------

        .IF  USERINT = 0
        .IF  ROM4K = 0
INITMSG .ASCII  'SELF TEST OK'
        .BYTE   0

        .IF  ROM8K = 1
        .IF  NEWTWIG = 0
CROMMSG .ASCII  'CPU ROM 1.08'
        .BYTE   0
        .ENDC
        .IF  NEWTWIG = 1
CROMMSG .ASCII  'CPU ROM 1.18'
        .BYTE   0
        .ENDC
        .ENDC

IORMMSG .ASCII  'IO ROM '
        .BYTE   0
CPUMSG  .ASCII  'CPU LOGIC FAILURE'
        .BYTE   0

        .ENDC			        ;{ROM4K}

RAMMSG  .ASCII  'MEMORY FAILURE'
        .BYTE   0
IOMSG   .ASCII  'IO LOGIC FAILURE'
        .BYTE   0
IOSMSG  .ASCII  'IO SLOT FAILURE'
        .BYTE   0
DSKMSG  .ASCII  'PLEASE INSERT DISK'
        .BYTE   0
BOOTERR .ASCII  'STARTUP FAILURE'
        .BYTE   0
DVCMSG  .ASCII  'DEVICE '
        .BYTE   0

ERRMSG  .ASCII  'ERROR '	        ;FOR ERROR CODE OUTPUT
        .BYTE   0
EXCPMSG .ASCII  'EXCEPTION'
        .BYTE   0

        .IF  ROM4K = 0
BOOTMSG .ASCII  'BOOTING...'
        .BYTE   0
        .ELSE
BOOTMSG .ASCII  'BOOTING'
        .BYTE   0
        .ENDC

BADBOOT .ASCII  'INVALID SELECTION'
        .BYTE   0

        .ENDC			        ;{USERINT}
        .IF     BURNIN = 1

BRNMSG  .ASCII  'POWER CYCLING AT '
        .BYTE   0
TIMMSG  .ASCII  'TIME IS '			       ; RM000
        .BYTE   0
TWGMSG  .ASCII  'DRIVE TEST'			       ; RM000
        .BYTE   0
LOOPMSG .ASCII  'LOOP COUNT IS '
        .BYTE   0
PMMSG   .ASCII  'PM BUS ERROR'
        .BYTE   0
TWGFAIL .ASCII  'FLOPPY TEST FAILED'
        .BYTE   0
TWGRSLT .ASCII  'FLOPPY ERROR COUNT IS '
        .BYTE   0

        .ENDC

        .IF  ROM4K = 0
        .IF  USERINT = 0
CONTMSG .ASCII  '2-CONTINUE  '
        .BYTE 0

LEV1MSG .ASCII  '1-RETRY  3-STARTUP FROM...  ?'
        .BYTE   0

LEV2MSG .ASCII  '1-DISPLAY  2-SET  3-CALL  '

        .IF ROM16K = 1
        .ASCII  '4-DUMP	 5-VERIFY  6-LOOP  '
        .ENDC

        .ASCII  '7-ADJUST VIDEO	 9-QUIT	 ?'
        .BYTE   0

        .ELSE

CHKMSG  .ASCII  'TESTING'
        .BYTE   0
        .ASCII  'TEST'		        ;French translation
        .BYTE   0
        .ASCII  'ES WIRD GETESTET'      ;German translation
        .BYTE   0

RTRYMSG .ASCII  'RESTART'
        .BYTE   0
        .ASCII  'RECOMMENCER'	        ;French
        .BYTE   0
        .ASCII  'NEU STARTEN'	        ;German
        .BYTE   0

CONTMSG .ASCII  'CONTINUE'
        .BYTE   0
        .ASCII  'CONTINUER'	        ;French
        .BYTE   0
        .ASCII  'WEITERMACHEN'	        ;German
        .BYTE   0

STRTMSG .ASCII  'STARTUP FROM'
        .BYTE   0
        .ASCII  'DEMARRER DE'	        ;French
        .BYTE   0
        .ASCII  'STARTEN VON'	        ;German
        .BYTE   0

PERIODS .ASCII  '...'
        .BYTE   0

MENUHDG .ASCII  'OPTIONS'
        .BYTE   0

DISPMSG .ASCII  'DISPLAY MEM   1'
        .BYTE   0
SETMSG  .ASCII  'SET MEMORY    2'
        .BYTE   0
CALLMSG .ASCII  'CALL PROGRAM  3'
        .BYTE   0

        .IF  ROM16K = 1
LPMSG   .ASCII  'LOOP ON TEST  4'
        .BYTE   0
        .ENDC

VIDMSG  .ASCII  'ADJUST VIDEO  5'
        .BYTE   0

        .IF  BURNIN = 1
CYCLMSG .ASCII  'POWER CYCLE   6'
        .BYTE   0
        .ENDC

QUITMSG .ASCII  'QUIT	       7'
        .BYTE   0

MENUID  .BYTE   KEY1,KEY2,KEY3		        ;menu id table

        .IF  ROM16K = 1
        .BYTE   KEY4
        .ENDC

        .BYTE   KEY5

        .IF  BURNIN = 1
        .BYTE   KEY6
        .ENDC

        .BYTE   KEY7

        .ENDC

        .IF  ROM16K = 1
        .IF  FULLSCC = 0
NOTAMSG .ASCII  'NOT YET AVAILABLE'
        .BYTE   0
        .ENDC

TSTMENU .ASCII  '1 - ROM'
        .BYTE   RET
        .ASCII  '2 - MMU'
        .BYTE   RET
        .ASCII  '3 - VIDEO'		        ;RM000
        .BYTE   RET
        .ASCII  '4 - PARITY'		        ;RM000
        .BYTE   RET
        .ASCII  '5 - PARA VIA'		        ;RM000
        .BYTE   RET
        .ASCII  '6 - KYBD VIA'		        ;RM000
        .BYTE   RET
        .ASCII  '7 - COPS'
        .BYTE   RET
        .ASCII  '8 - SCC'
        .BYTE   RET
        .ASCII  '9 - DISK'
        .BYTE   RET
        .ASCII  'A - CLOCK'
        .BYTE   RET
        .ASCII  'B - MEMORY'
        .BYTE   RET
        .ASCII  'C - IO SLOTS'
        .BYTE   0
        .ENDC

        .IF  USERINT = 0
ADDRMSG .ASCII  'ADDRESS?>'
        .BYTE   0
DATAMSG .ASCII  'DATA ?	 >'
        .BYTE   0
CNTMSG  .ASCII  'COUNT ? >'
        .BYTE   0
DRVMSG  .ASCII  'DRIVE ? >'
        .BYTE   0
DVCEMSG .ASCII  'DEVICE ?>'
        .BYTE   0
TSTMSG  .ASCII  'TEST  ? >'
        .BYTE   0

        .ELSE
ADDRMSG .ASCII  'ADDRESS ?'
        .BYTE   0
DATAMSG .ASCII  'DATA ?'
        .BYTE   0
CNTMSG  .ASCII  'COUNT ?'
        .BYTE   0
TSTMSG  .ASCII  'TEST ?'
        .BYTE   0

        .ENDC

WHATMSG .ASCII  'WHAT ?'
        .BYTE   0

        .ENDC			        ;{ROM4K}

        .IF  ROM4K = 1
        .ORG    $0FFC
VRSN    .WORD   $0027	        ;version 0.27
        .ENDC

        .IF  ROM8K = 1
        .ORG    $1FFC
        .IF  NEWTWIG = 0
VRSN    .WORD   $0108	        ;version 1.08
        .ENDC
        .IF  NEWTWIG = 1
VRSN    .WORD   $0118	        ;version 1.18
        .ENDC
        .ENDC

        .IF  ROM16K = 1
        .ORG    $3FF4	        ;			        CHG005

;************ COPYRIGHT NOTICE ***************************************
HDGMSG  .ASCII  'C84APPLE'      ;			        CHG005
;*********************************************************************

VRSN    .BYTE   $02	        ;version 2		        CHG001
REV     .ASCII  'H'	        ; rev H			        CHG001
        .ENDC


LAST    .WORD   $0000	        ;checksum word for ROM test

        .END

